package com.ai.opc;

import com.ai.common.CommonResponse;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.milo.opcua.sdk.client.api.identity.AnonymousProvider;
import org.eclipse.milo.opcua.sdk.client.api.identity.UsernameProvider;
import org.eclipse.milo.opcua.stack.core.AttributeId;
import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy;
import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;
import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText;
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
import org.eclipse.milo.opcua.stack.core.types.enumerated.MonitoringMode;
import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn;
import org.eclipse.milo.opcua.stack.core.types.structured.MonitoredItemCreateRequest;
import org.eclipse.milo.opcua.stack.core.types.structured.MonitoringParameters;
import org.eclipse.milo.opcua.stack.core.types.structured.ReadValueId;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author jiaok
 * @Date 2024-11-11 11:16
 */
@Slf4j
@Service
public class KEPOpcDemo5 {


//     @Value("${opc.endPointUrl}")
     private   static String endPointUrl = "opc.tcp://127.0.0.1:49320";

    public static void main(String[] args) {
        try {
            //创建OPC UA客户端
            OpcUaClient opcUaClient = createClient();

            //开启连接
            opcUaClient.connect().get();
//            // 订阅消息
            subscribe(opcUaClient);

            // 写入
//            writeValue(opcUaClient);

            // 读取
//            readValue(opcUaClient);

            // 关闭连接
            opcUaClient.disconnect().get();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
/**
     * 创建OPC UA客户端
     *
     * @return
     * @throws Exception
     */
    public static OpcUaClient createClient()  {
        try {
            Path securityTempDir = Paths.get(System.getProperty("java.io.tmpdir"), "security");
            Files.createDirectories(securityTempDir);
            if (!Files.exists(securityTempDir)) {
                throw new Exception("unable to create security dir: " + securityTempDir);
            }
            return OpcUaClient.create(endPointUrl,
                    endpoints ->
                            endpoints.stream()
                                    .filter(e -> e.getSecurityPolicyUri().equals(SecurityPolicy.None.getUri()))
                                    .findFirst(),
                    configBuilder ->
                            configBuilder
                                    .setApplicationName(LocalizedText.english(""))
                                    .setApplicationUri("")
                                    //访问方式 new AnonymousProvider()
                                    .setIdentityProvider(new UsernameProvider("ua_test", "123456"))
//                                    .setIdentityProvider(new AnonymousProvider())
                                    .setRequestTimeout(UInteger.valueOf(5000))
                                    .build()
            );
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    public static void subscribe(OpcUaClient client) throws Exception {
        //创建发布间隔1000ms的订阅对象
        client.getSubscriptionManager()
                .createSubscription(1000.0)
                .thenAccept(t -> {
                    //节点ns=2;s=test.device2.test2
                    NodeId nodeId = new NodeId(2, "GZM.c_m_j.t1");
                    ReadValueId readValueId = new ReadValueId(nodeId, AttributeId.Value.uid(), null, null);
                    //创建监控的参数
                    MonitoringParameters parameters = new MonitoringParameters(UInteger.valueOf(1), 1000.0, null, UInteger.valueOf(10), true);
                    //创建监控项请求
                    //该请求最后用于创建订阅。
                    MonitoredItemCreateRequest request = new MonitoredItemCreateRequest(readValueId, MonitoringMode.Reporting, parameters);
                    List<MonitoredItemCreateRequest> requests = new ArrayList<>();
                    requests.add(request);
                    //创建监控项，并且注册变量值改变时候的回调函数。
                    t.createMonitoredItems(
                            TimestampsToReturn.Both,
                            requests,
                            (item, id) -> item.setValueConsumer((it, val) -> {
                                System.out.println("=====订阅nodeid====== :" + it.getReadValueId().getNodeId());
                                System.out.println("=====订阅value===== :" + val.getValue().getValue());
                            })
                    );
                }).get();

        //持续订阅
        Thread.sleep(Long.MAX_VALUE);
    }

    public  void readValue(OpcUaClient client) {
        try {
            NodeId nodeId = new NodeId(2, "GZM.c_m_j.t1");

            DataValue value = client.readValue(0.0, TimestampsToReturn.Both, nodeId).get();

            System.out.println("=====读取ua1====：" + value.getValue().getValue());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public  void readAppointNodeValue(OpcUaClient client,NodeId nodeId) {
        try {
            DataValue value = client.readValue(0.0, TimestampsToReturn.Both, nodeId).get();

            System.out.println("=====读取ua1====：" + value.getValue().getValue());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public CommonResponse getOpcConnect(Integer nameSpaceIndex,String identifier) {

        OpcUaClient client = createClient();
        if (null == client){
            return CommonResponse.error("opc连接失败");
        }else {
            log.info("=======================   OOO     PPPPP    CCCC  ==========================");
            log.info("=======================  O   O    P    P   C      ===========================");
            log.info("=======================  O   O    PPPPP    C     ===========================");
            log.info("=======================  O   O    P        C      ===========================");
            log.info("=====================     OOO     P         CCCC   ===========================");
            log.info("===========================  OPC连接成功 :{} ===========================",endPointUrl);

            NodeId nodeId = new NodeId(nameSpaceIndex, identifier);
            readAppointNodeValue(client,nodeId);

            return CommonResponse.ok("opc连接成功");
        }

    }
}
